package com.ssfeng.youxia.schedule;

import com.ssfeng.youxia.commons.SpringApplicationContextUtil;
import com.ssfeng.youxia.entity.ScheduleTask;
import com.ssfeng.youxia.service.IScheduleTaskService;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.util.*;

/**
 * Created by liyuhang on 2019-09-16.
 * 定时任务调度器
 */
@Component
public class YouxiaScheduler {

    private static final Logger logger = LoggerFactory.getLogger(YouxiaScheduler.class);

    @Autowired
    private Scheduler scheduler;


    @Autowired
    private IScheduleTaskService scheduleTaskService;

    /***
     * 调度定时任务
     * @throws SchedulerException
     * @throws NoSuchMethodException
     * @throws ClassNotFoundException
     */
    @Scheduled(cron = "0 1/5 * * * ?")
    public void scheduleTimeTask() throws SchedulerException, NoSuchMethodException, ClassNotFoundException {

        List<com.ssfeng.youxia.entity.ScheduleTask> taskList = scheduleTaskService.list();
        Map<String, Set<String>> groupTaskMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(taskList)) {
            for (com.ssfeng.youxia.entity.ScheduleTask scheduleTask : taskList) {

                if (CollectionUtils.isEmpty(groupTaskMap.get(scheduleTask.getTaskGroupName()))) {
                    groupTaskMap.put(scheduleTask.getTaskGroupName(), new HashSet<>());
                }
                groupTaskMap.get(scheduleTask.getTaskGroupName()).add(scheduleTask.getTaskName());

                TriggerKey triggerKey = new TriggerKey(scheduleTask.getTaskName(), scheduleTask.getTaskGroupName());
                JobKey jobKey = new JobKey(scheduleTask.getTaskName(), scheduleTask.getTaskGroupName());

                CronTrigger trigger= (CronTrigger) scheduler.getTrigger(triggerKey);
                if (trigger == null) {
                    //新增任务
                    this.addScheduleTask(scheduleTask);
                    continue;
                }

                String oldExp = trigger.getCronExpression();
                if (!oldExp.equals(scheduleTask.getCron())) {
                    //重新调度
                    CronTrigger newtrigger = TriggerBuilder.newTrigger()
                            .withIdentity(scheduleTask.getTaskName(),scheduleTask.getTaskGroupName())
                            .withSchedule(CronScheduleBuilder.cronSchedule(scheduleTask.getCron()))
                            .build();
                    scheduler.rescheduleJob(triggerKey, newtrigger);
                }
            }
        }

        //删除定时任务
        List<String> groupList = scheduler.getJobGroupNames();
        if (!CollectionUtils.isEmpty(groupList)) {
            for (String group : groupList) {
                Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(group));
                if (!CollectionUtils.isEmpty(jobKeys)) {
                    for (JobKey jobKey : jobKeys) {
                        String taskName = jobKey.getName();
                        if (groupTaskMap.get(group) == null || !groupTaskMap.get(group).contains(taskName)) {
                            this.deleteScheduleTask(jobKey);
                        }
                    }
                }
            }
        }
    }

    /***
     * 新增定时任务
     * @param task
     * @throws NoSuchMethodException
     * @throws ClassNotFoundException
     * @throws SchedulerException
     */
    public void addScheduleTask(ScheduleTask task) throws NoSuchMethodException, ClassNotFoundException, SchedulerException {
        CronTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(task.getTaskName(), task.getTaskGroupName())
                .withSchedule(CronScheduleBuilder.cronSchedule(task.getCron()))
                .build();
        MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean();
        Object targetObject = SpringApplicationContextUtil.getContext().getBean(task.getTaskClassName());
        if (StringUtils.isEmpty(targetObject)) {
            logger.info("定时任务:taskClassName:{}没有获取到对应的Spring Bean");
            return;
        }
//        jobDetail.setTargetClass(SessionScheduler.class);
        jobDetail.setTargetObject(targetObject);
        jobDetail.setTargetMethod(task.getTaskMethod());
        jobDetail.setName(task.getTaskName());
        jobDetail.setGroup(task.getTaskGroupName());
        jobDetail.setConcurrent(false);
        jobDetail.afterPropertiesSet();
        scheduler.scheduleJob(jobDetail.getObject(), trigger);
    }

    /***
     * 删除定时任务
     * @param jobKey
     * @throws SchedulerException
     */
    public void deleteScheduleTask(JobKey jobKey) throws SchedulerException {
        TriggerKey triggerKey = new TriggerKey(jobKey.getName(),jobKey.getGroup());
        scheduler.pauseTrigger(triggerKey);// 停止触发器
        scheduler.unscheduleJob(triggerKey);// 移除触发器
        scheduler.deleteJob(jobKey);// 删除任
    }


    /***
     * 初始化调度器
     * @throws SchedulerException
     */
    @PostConstruct
    public void scheduleInit() throws SchedulerException {
        scheduler.start();
    }


}
